package org.spiderflow.core.expression.parsing.ast.literal;

import org.spiderflow.core.expression.ExpressionTemplate;
import org.spiderflow.core.expression.ExpressionTemplateContext;
import org.spiderflow.core.expression.parsing.Span;
import org.spiderflow.core.expression.parsing.ast.Expression;
import org.spiderflow.core.expression.parsing.token.Token;
import org.spiderflow.core.expression.parsing.token.TokenType;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Represents a map literal of the form <code>{ key: value, key2: value, ... }</code> which can be nested.
 */
public class MapLiteral extends Expression {
    private final List<Token> keys;
    private final List<Expression> values;

    public MapLiteral(Span span, List<Token> keys, List<Expression> values) {
        super(span);
        this.keys = keys;
        this.values = values;
    }

    public List<Token> getKeys() {
        return keys;
    }

    public List<Expression> getValues() {
        return values;
    }

    @Override
    public Object evaluate(ExpressionTemplate template, ExpressionTemplateContext context) throws IOException {
        Map<String, Object> map = new HashMap<>();
        for (int i = 0, n = keys.size(); i < n; i++) {
            Object value = values.get(i).evaluate(template, context);
            Token tokenKey = keys.get(i);
            String key = tokenKey.getSpan().getText();
            if (tokenKey.getType() == TokenType.STRING_LITERAL) {
                key = (String) new StringLiteral(tokenKey.getSpan()).evaluate(template, context);
            } else if (key != null && key.startsWith("$")) {
                Object objKey = context.get(key.substring(1));
                if (objKey != null) {
                    key = objKey.toString();
                } else {
                    key = null;
                }
            }
            map.put(key, value);
        }
        return map;
    }
}